/*************************************************************************
	> File Name: 016.prim.cpp
	> Author: Maureen 
	> Mail: Maureen@qq.com 
	> Created Time: 六  6/26 13:56:30 2021
 ************************************************************************/

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

//prim算法：最小生成树

struct node {
    int now, v; //now:所在的点的编号 v：通过哪条边到达的这个点的边的边权
    bool operator<(const node &b) const {
        //因为优先队列默认是个大顶堆，为了让v值更小的结构体排在更前面，那么结构体中的v越小，结构体就越靠前
        return this->v > b.v; //如果this->v > b.v成立, 那么结构体node this < node b成立 
    }
};

struct edge {
    int e, v, next;
};

edge edg[400005];
int n, m, ans, edg_cnt, head[5005], num[5005], mark[5005]; //mark标记点是否被访问过, num[i]表示在最小生成树中i与其他点相连的那条边的权值
int cnt; //点的个数

void add_edg(int a, int b, int c) {
    edg[edg_cnt].e = b;
    edg[edg_cnt].v = c;
    edg[edg_cnt].next = head[a];
    head[a] = edg_cnt++;
}

int main() {
    memset(head, -1, sizeof(head));
    memset(num, 0x3f, sizeof(num));
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        add_edg(a, b, c);
        add_edg(b, a, c);
    }
 
    priority_queue<node> que;
    que.push((node){n, 0}); //任意点为起点，将起点放入队列中，此处选择的n号点,和n号点相连的边的边权为0
    num[n] = 0; //和n号点相连的边的边权
    while (!que.empty()) {
        node temp = que.top();
        que.pop();
        if (mark[temp.now] == 1) { //判断该点是否为第一次访问
            continue;
        }
        mark[temp.now] = 1;
        ans += temp.v; //第一次访问
        cnt++;
        if (cnt == n) { //求完了所有边
            break;
        }
        for (int i = head[temp.now]; i != -1; i = edg[i].next) {
            int e = edg[i].e, v = edg[i].v;
            if (mark[e] == 0 && num[e] > v) {
                num[e] = v;
                que.push((node){e, v});
            }
        }
    }
    if (cnt == n) {
        cout << ans << endl;
    } else {
        cout << "orz" << endl;
    }
}


